'''The bkn.bibtex.error module defines the exception classes used by the
bkn.bibtex package.

The base exception class is BKNBibtexError.

@copyright: (c) 2010, Benjamin Kalish

@license:
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
'''

import sys


class BKNBibtexError(Exception):
    '''The base class for errors in the bkn.bibtex package.'''
    pass


class FormatNotSupportedError(BKNBibtexError):
    '''This error is raised by if an attempt is made to read or write a
    bibliography in a format which is not supported.'''
    def __init__(self, format):
        '''Creates a new FormatNotSupportedError
        
        @param format:
            The name of the format which is not supported.
        @type format: string
        '''
        
        self.format = format
        '''The format which was requested.'''
    
    def __str__(self):
        '''Returns a user friendly error message.

        @rtype: string
        '''
        
        return 'the ' + self.format + '''format is not supported. See the
        documentation for a list of supported formats.'''


class BibFileSyntaxError(BKNBibtexError):
    '''This error is rased when trying to import a bibliography from a
    serialization which contains syntax errors.
    
    '''
    def __init__(self, parse_syntax_error, filename):
        '''Creates a new BibFileSyntaxError.
        
        @param parse_syntax_error:
            A string describing the nature of the error. This should give
            a line and column number if possible.
        @type parse_syntax_error: string
        @param filename:
            A string naming the data source which contained the error. This
            will usually be a file name, but need not be.
        @type filename: string
        '''
        
        self.parse_syntax_error = parse_syntax_error
        '''A string describing the nature of the error.'''
        
        self.filename = filename
        '''A descriptive name for the data source which contained the error.
        This is often a file name, but need not be.'''
    
    def __str__(self):
        '''Returns a user friendly error message including both the filename
        and parse_syntax_error.

        @rtype: string
        '''
        
        return 'could not parse "' + self.filename + '": ' + \
               str(self.parse_syntax_error)

class NameError(BKNBibtexError):
    '''An error returned when a name can not be parsed.'''
    pass

class InvalidRecordError(BKNBibtexError):
    '''An error returned when a record is found to be invalid.'''
    pass

class RecordNotFoundError(BKNBibtexError):
    '''An error returned when the specified record can not be found in the given context.'''
    pass

class InvalidReferenceError(BKNBibtexError):
    '''An error returned when a reference is malformed.
    
    A reference could be malformed because it doesn't begin with the
    proper prefix (either '@' or '@@") or because it isn't a valid URI.
    '''
    pass
    
class InvalidResponseError(BKNBibtexError):
    '''An error returned when, in trying to resolve a reference, a
    response is recieved but is invalid.'''
    pass

class ExternalError(BKNBibtexError):
    '''An error returned when a problem is encountered in interacting with the system.
    
    This error is used when:
        - an external executable cannot be found
        - an external executable gives unexpected output
    '''
    pass

class BibTeXError(BKNBibtexError):
    '''An error returned when the bibtex executable runs as expected but returns an error.'''
    pass
    
class BadAttributeNameError(BKNBibtexError):
    '''An error returned when a bad attribute name is encountered.
    
    A bad attribute name is one that is not a string (or Unicode object)
    or is the empty string.
    '''
    pass

class BKNBibtexWarning(UserWarning):
    '''The base class for warnings in the bkn.bibtex package.'''
    pass
    
class AttributeCollisionWarning(BKNBibtexWarning):
    '''A warning generated when serializing a Bibliography requires
    renaming attributes to avoid collision.'''

    def __init__(self, attr_name, attr_replacement, format):
        self.attr_name = attr_name
        '''The name of attribute.'''
        self.attr_replacement = attr_replacement
        '''The name which will be used instead.'''
        self.format = format
        '''The name of the output format.'''

    def __str__(self):
        return (
            "Attribute '{0.attr_name}' is a reserved attribute in the \
{0.format} format and will be renamed '{0.attr_replacement}' to avoid \
collision in {0.format} output.".format(self))